﻿using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.LogDomain;
using Zocono.WCS.Domain.PlcBytesObject;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Infrastructure.ApllicationDto.Enums;
using Zocono.WCS.WMSApiDomain.WebApi;

namespace Zocono.WCS.Domain.EquipmentProcessDomain.PlanarGeneralMessage
{
    /// <summary>
    /// 到达目标工位完成任务
    /// </summary>
    public class ArriveTargetService : IPlanarGeneralPlcActionProcessService
    {
        private readonly IRedisHelper _IRedisHelper;
        private readonly ILogUtil _LogUtil;
        private readonly ISnowflake _Snowflake;
        private readonly IPlcConnectionPool _PlcConnectionPool;
        private readonly IWorkTaskInfoRepository _WorkTaskInfoRepository;
        private readonly IRouteDetailInfoRepository _RouteDetailInfoRepository;
        private readonly IPlcWriteDbInfoRepository _PlcWriteDbInfoRepository;
        private readonly ITaskRouteDetailRecordInfoRepository _TaskRouteDetailRecordInfoRepository;
        private readonly IPlcConnectionStateInfoRepository _IPlcConnectionStateInfoRepository;
        private readonly IRunLogInfoService _IRunLogInfoService;
        private readonly IPlcReadDbInfoRepository _PlcReadeDbInfoRepository;

        public ArriveTargetService(IRedisHelper iRedisHelper, ILogUtil logUtil
            , ISnowflake snowflake
            , IPlcConnectionPool plcConnectionPool
            , IWorkTaskInfoRepository workTaskInfoRepository
            , IRouteDetailInfoRepository routeDetailInfoRepository
            , IPlcWriteDbInfoRepository plcWriteDbInfoRepository
            , ITaskRouteDetailRecordInfoRepository taskRouteDetailRecordInfoRepository
            , IPlcConnectionStateInfoRepository plcConnectionStateInfoRepository
            , IPlcReadDbInfoRepository plcReadDbInfoRepository
             , IRunLogInfoService runLogInfoService)
        {
            _IRedisHelper = iRedisHelper;
            _LogUtil = logUtil;
            _Snowflake = snowflake;
            _PlcConnectionPool = plcConnectionPool;
            _WorkTaskInfoRepository = workTaskInfoRepository;
            _RouteDetailInfoRepository = routeDetailInfoRepository;
            _PlcWriteDbInfoRepository = plcWriteDbInfoRepository;
            _TaskRouteDetailRecordInfoRepository = taskRouteDetailRecordInfoRepository;
            _IPlcConnectionStateInfoRepository = plcConnectionStateInfoRepository;
            _PlcReadeDbInfoRepository = plcReadDbInfoRepository;
            _IRunLogInfoService = runLogInfoService;
        }

        public async Task ProcessActionMessageAsync(BytesObjectBase plcActionMessage, BytesObjectBase wcsActionMessage, EquipmentDbObject planarEquipmentDbObject/*, BytesObjectBase plcStateMassge*/)
        {

            /*
             * 处理逻辑
             * 1. 验证plc是否在线
             * 2. 验证设备是否报警
             * 3. 验证wcs任务,验证wcs当前任务节点是否结束节点
             * 4. 存在，则组织报文，写入plc
             * 5. 写入plc是否成功，成功，结束任务，上报wms,失败，不往下操作
             */
            var plcMessage = plcActionMessage as PlanarGeneralPlcActionBO;//Plc的动作报文
            var wcsMessage = wcsActionMessage as PlanarGeneralWcsActionBO;//Wcs的动作报文
            plcMessage.PalletBarcode = plcMessage.PalletBarcode.Trim();
            //var plcStateBo = plcStateMassge as PlcOnLineStateBO;//Plc在线离线报文 没有设备信息
            RunLogInfo runLogInfo = new RunLogInfo();
            runLogInfo.ContainerBarcode = plcMessage.PalletBarcode;
            runLogInfo.EquipmentCode = plcMessage.EquipmentCode;
            runLogInfo.RunType = "到达目标工位";

            runLogInfo.RunLog = "到达目标工位任务开始";

            var plcConn = _PlcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID);
            if (plcConn == null)
            {
                //runLogInfo.RunLog = $"获取连接({plcMessage.PlcConnectionID})失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,连接池无连接({plcMessage.PlcConnectionID})");
                return;
            }
            var plcIPStates = await _IPlcConnectionStateInfoRepository.GetFirstAsync(l => l.PlcConnectionID == plcMessage.PlcConnectionID && l.Connected == true);
            if (plcIPStates == null)
            {
                //runLogInfo.RunLog = $"{plcConn.IP}plc已离线";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,获取连接({plcMessage.PlcConnectionID})失败");
                return;
            }

            //if (plcMessage.AlrmCode != 0)
            //{
            //    runLogInfo.RunLog = $"报警,报警代码：{plcMessage.AlrmCode}";
            //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    return;
            //}


            //4. 组织报文，写入plc
            var objectType = typeof(PlanarGeneralWriteWcsAction).Name;
            var writeConfig = await _PlcWriteDbInfoRepository.GetFirstAsync(s => s.EquipmentCode == plcMessage.EquipmentCode && s.ObjectType == objectType);
            if (writeConfig == null)
            {
                //runLogInfo.RunLog = $"获取PLC写入配置失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,获取PLC写入配置失败！请检查配置！");
                return;
            }

            PlanarGeneralWriteWcsAction writeAlrmBo = new PlanarGeneralWriteWcsAction(
                writeConfig.PlcConnectionId,
                writeConfig.ID,
                writeConfig.DbCode,
                writeConfig.DbStart,
                objectType,
                plcMessage.EquipmentCode.ToInt32(),
                0,
                //toEquiment.ToInt32(),
                0,
                0,
                "",
                0,
                0);


            //校验plc信息是否有托盘码
            if (string.IsNullOrEmpty(plcMessage.PalletBarcode) || plcMessage.PalletBarcode.Length != 10)
            {
                writeAlrmBo.AlrmCode = 102;
                writeAlrmBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeAlrmBo.DbCode, writeAlrmBo.DbStart, writeAlrmBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            //3. 验证wcs任务,验证wcs当前任务节点是否结束节点
            var exp = Expressionable.Create<WorkTaskInfo>();
            exp.AndIF(true, it => it.PalletCode == plcMessage.PalletBarcode && it.TaskState == EnumTaskState.Executing);
            //exp.AndIF(true, it => it.TaskCode == plcMessage.TaskCode && it.TaskState == EnumTaskState.Executing);
            var task = await _WorkTaskInfoRepository.GetFirstAsync(exp.ToExpression());
            if (task == null)
            {
                var expL = Expressionable.Create<WorkTaskInfo>();
                expL.AndIF(true, it => it.PalletCode == plcMessage.PalletBarcode && it.TaskState == EnumTaskState.Finish);
                //exp.AndIF(true, it => it.TaskCode == plcMessage.TaskCode && it.TaskState == EnumTaskState.Executing);

                //task = await _WorkTaskInfoRepository.GetFirstAsync(expL.ToExpression());
                task = await _WorkTaskInfoRepository.AsSugarClient().Queryable<WorkTaskInfo>().Where(expL.ToExpression()).OrderBy(it=>it.CurrentUpdateTime,OrderByType.Desc).FirstAsync();

                if (task != null)
                {
                    string[] toEq = { "100001", "100003", "100005", "100007", "100009", "100011", "100013", "100015" };
                    string[] cuEq = { "110013", "110017", "110039", "110043", "110073", "110077", "110107", "110111", "110123" };
                    if (!(toEq.Contains(task.CurrentToEquipment) && cuEq.Contains(plcMessage.EquipmentCode)))
                    {
                        //设备号不是任务的最终目标设备
                        if (task.WmsToPosition != plcMessage.EquipmentCode && task.CurrentToEquipment != plcMessage.EquipmentCode)
                        {
                            _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,任务号({plcMessage.TaskCode})当前设备号不是目标设备号");
                            writeAlrmBo.AlrmCode = 119;
                            writeAlrmBo.ActionType = 99;
                            var flag = await plcConn.WriteDbAsync(writeAlrmBo.DbCode, writeAlrmBo.DbStart, writeAlrmBo.Deserialize());
                            _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                            return;
                        }
                    }
                }
                else
                {
                    //runLogInfo.RunLog = $"任务号({plcMessage.PalletBarcode})执行中的任务数据异常，请检查此任务状态";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    //writeAlrmBo.ActionType = 0;
                    //writeAlrmBo.AlrmCode = 7;
                    //var write = await plcConn.WriteDbAsync(writeAlrmBo.DbCode, writeAlrmBo.DbStart, writeAlrmBo.Deserialize());
                    writeAlrmBo.AlrmCode = 122;
                    writeAlrmBo.ActionType = 99;
                    var flag = await plcConn.WriteDbAsync(writeAlrmBo.DbCode, writeAlrmBo.DbStart, writeAlrmBo.Deserialize());
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                    _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,执行中的任务数据异常，请检查此任务状态");
                    return;
                }
            }

            var routeDetailInfo = await _RouteDetailInfoRepository.GetByIdAsync(task.CurrentRounteDetailID);
            if (routeDetailInfo.IsEnd == false)
            {
                //runLogInfo.RunLog = $"任务号({plcMessage.TaskCode})任务当前的路径明细节点不是结束节点";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                //writeAlrmBo.ActionType = 0;
                //writeAlrmBo.AlrmCode = 9;
                //var write = await plcConn.WriteDbAsync(writeAlrmBo.DbCode, writeAlrmBo.DbStart, writeAlrmBo.Deserialize());
                _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,任务号({plcMessage.TaskCode})任务当前的路径明细节点不是结束节点");
                writeAlrmBo.AlrmCode = 119;
                writeAlrmBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeAlrmBo.DbCode, writeAlrmBo.DbStart, writeAlrmBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            
            //plc报文什么握手类型则回什么握手类型
            PlanarGeneralWriteWcsAction writeBo = new PlanarGeneralWriteWcsAction(
                writeConfig.PlcConnectionId,
                writeConfig.ID,
                writeConfig.DbCode,
                writeConfig.DbStart,
                objectType,
                plcMessage.EquipmentCode.ToInt32(),
                plcMessage.ActionType,
                plcMessage.ToEquipmentCode,
                task.TaskCode,
                task.PalletCode,
                plcMessage.PalletType,
                alrmCode: plcMessage.AlrmCode);

            

            

            //var plcConfig = await _PlcReadeDbInfoRepository.GetFirstAsync(l => l.ID == plcMessage.PlcReadDbID);

            ////入库台
            //byte[] bytesPu = await plcConn.ReadDbAsync(plcConfig.DbCode, plcConfig.DbStart, plcConfig.DbLength);
            //if (bytesPu == null)
            //{
            //    runLogInfo.RunLog = $"读DB失败";
            //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    return;
            //}

            //5.写入成功，结束任务，上报wms
            task.TaskState = EnumTaskState.Finish;
            task.UpdateTime = DateTime.Now;
            task.CurrentDetailTaskState = EnumDetailTaskState.Finish;
            task.CurrentUpdateTime = DateTime.Now;
            task.TaskProcessState = EnumTaskProcessState.PlanerCompleted;

            WMSApiDomain.WebApi.HeaderResult<bool> uploadResult = new();
            try
            {
                uploadResult = await WCSMessageWithWMSApi.WCSNoticeTaskAutoCompleteAsync(task.WmsTaskCode, plcMessage.PalletBarcode, task.CurrentToEquipment);
                if (uploadResult.IsSucceed)
                {
                    //runLogInfo.RunLog = $"任务号{task.TaskCode}上传WMS成功";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    //task.UploadWmsState = EnumUploadWmsState.Succeed;
                    runLogInfo.RunLog = $"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】任务号{task.TaskCode}上传WMS成功";
                    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    task.UploadWmsState = EnumUploadWmsState.Succeed;
                }
                else
                {
                    //runLogInfo.RunLog = $"任务号{task.TaskCode}上传WMS失败;WMS回应:{uploadResult.Message}";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    //task.UploadWmsState = EnumUploadWmsState.Failed;
                    task.UploadWmsState = EnumUploadWmsState.Failed;
                    _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,任务号{task.TaskCode}上传WMS失败;WMS回应:{uploadResult.Message}");
                    writeBo.AlrmCode = 120;
                    writeBo.ActionType = 99;
                    var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                }
                task.UploadWmsTime = DateTime.Now;
            }
            catch (Exception ex)
            {
                //runLogInfo.RunLog = $"任务号{task.TaskCode}上传WMS异常，异常信息：{ex.Message}";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,任务号{task.TaskCode}上传WMS异常，异常信息：{ex.Message}");
                writeBo.AlrmCode = 121;
                writeBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }


            //if (upResult)
            //{
            //前面都通过，则任务开始
            writeBo.ActionType = plcMessage.ActionType;
            var writeResult = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize(), plcMessage.EquipmentCode);

            if (writeResult == false)
            {
                //runLogInfo.RunLog = $"PLC(IP{plcConn.IP},写入报文失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

                _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,PLC(IP{plcConn.IP},写入报文失败");
                return;
            }

            //更新WCS任务
            await _WorkTaskInfoRepository.UpdateAsync(task);

            runLogInfo.RunLog = $"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】到达目标任务处理成功，写入报文成功！报文内容：{JsonConvert.SerializeObject(writeBo)}";
            await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //}
            //else
            //{
            //    _LogUtil.Error($"到达目标工位：托盘【{plcMessage.PalletBarcode}】到达目标工位，PLC设备【{plcMessage.EquipmentCode}】,任务号{task.TaskCode}上传WMS更新数据失败");
            //    writeBo.AlrmCode = 123;
            //    writeBo.ActionType = 99;
            //    var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
            //    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
            //}
        }
    }
}
